/* 
 * File:   Minimizer.cpp
 * Author: Hamed Rafi
 *         Royal Institute of Technology
 *
 *         hamed.rafi@gmail.com
 * 
 * Created on November 23, 2010, 11:20 AM
 */

#include "Minimizer.h"

Minimizer::Minimizer() {
}

Minimizer::Minimizer(const Minimizer& orig) {
}

Minimizer::~Minimizer() {
}

void Minimizer::createFromFile(const char* fileName){

    readFile(fileName);
//    createFromBin(NULL);
}

void Minimizer::readFile(const char* addr){
//    ifstream inputFile;
//    inputFile.open(addr, ios::binary);
//    inputFile.seekg(0,ios::end);
//    seqLength = inputFile.tellg();
//    inputFile.seekg(0,ios::beg);
//    sequence = new char[seqLength - 1];
//    inputFile.read(sequence,seqLength);
//    inputFile.close();

    unsigned long long int binCounter;
    seqLength = 17;
    sequence = new char[seqLength-1];
    unsigned long long int i=0;
    for(i=1000; i<1256;i++){
        cout << "Perm No. " << i << ": ";
        binCounter = i;
        for(int j=0; j<seqLength-1 ;j++){
            if((binCounter)&1)
                sequence[j] = '1';
            else sequence[j] = '0';
            binCounter>>=1;
            cout << sequence[j];
        }
        cout << ": ";
        createFromBin(NULL);
        applyRules();
        print();
    }
//        createFromBin(NULL);
//        applyRules();
//        print();
}

void Minimizer::createFromBin(const char* binSeq){
    int halfLen=seqLength>>1;
    TupleK* gl = new TupleK(halfLen);
    TupleK* gr = new TupleK(halfLen);
    
    varNum = (int)log2(seqLength);
    int zeros=0, ones=0;
    LogicValue value;
    for(int i=0, j=halfLen-1; i< seqLength-1; i++){
        if(sequence[i]=='1'){
            if(!(i & (1<<varNum-1)))
                zeros++;
            else
                ones++;
        }
        value = (sequence[i]=='1')?logic_1:logic_0;
        if(i<(halfLen)){
            gl->SetValueAt(j--,value);
        }
        else{
            gr->SetValueAt(halfLen-(++j)-1,value);
        }
    }

    TupleK** zeroList = new TupleK*[zeros];
    TupleK** oneList = new TupleK*[ones];
    zeros = ones = 0;
    for(int i=0; i< seqLength-1; i++){
        if(sequence[i]=='1'){
            if(!(i & (1<<varNum-1))){
                zeroList[zeros] = new TupleK(varNum);
                zeroList[zeros]->setTuple(i);
//                zeroList[zeros]->print();
                zeros++;
            }
            else{
                oneList[ones] = new TupleK(varNum);
                oneList[ones]->setTuple(i);
//                oneList[ones]->print();
                ones++;
            }
        }
    }

//
//    cout << zeros << ":" << ones << endl;
//    gl->print();
//    gr->print();
    binaryTree = new BTree(varNum);

    BNode* nodeL = new BNode(varNum);
    nodeL->SetNodeName("left");
    nodeL->SetGFunc(gl);
    BNode* nodeR = new BNode(varNum);
    nodeR->SetNodeName("right");
    nodeR->SetGFunc(gr);

    binaryTree->GetRoot()->SetChildL(nodeL);
    binaryTree->GetRoot()->SetChildR(nodeR);
    if(zeros>1)
        nodeL->process0(zeroList, zeros);
    else if(zeros==1)
        nodeL->SetTuple(*zeroList);
    
    if(ones>1)
        nodeR->process0(oneList, ones);
    else if(ones==1)
        nodeR->SetTuple(*oneList);
    
//    cout << endl;
}

void Minimizer::traverse(){

}

void Minimizer::applyRules(){
//    cout << "Applying boolean algebra rules ..." << endl;
    BNode* dummy= binaryTree->GetRoot();
    dummy->applyRules();
}

void Minimizer::print(){
    cout << "f0 <= " << binaryTree->GetRoot()->printSimplified()<< ";" << endl;
}